// Alternate Realms - Person Header
// Copyright 2006 Mike Behlen

// FILE DESCRIPTION:
// Defines a Person and also a group of people (Crowd)

// TODO:
// Nothing. :)

class Person {
public:
  Person (string, short, short, short, short, short, short, short);
  ~Person () {};

  // General character trait accessor functions
  inline const string getName() { return name; }
  inline const short getCharclass() { return charclass; }
  inline const short getLevel() { return level; }
  inline const short getStr() { return str; }
  inline const short getDex() { return dex; }
  inline const short getCon() { return con; }
  inline const short getInt() { return inte; }
  inline const short getWis() { return wis; }
  inline const short getCha() { return cha; }
  inline const short getHP() { return hp; }
  inline const short getMaxHP() { return maxhp; }
  inline const short getAC() { return ac; }
  inline const short getXP() { return xp; }

  // HP / XP manipulation methods
  short setHP(short php) { if (php > maxhp) { hp = maxhp; } else if (php < 0) { hp = 0; } else { hp = php; } return hp; }
  short addHP(short php) { hp = hp + php; if (hp > maxhp) { hp = maxhp; } return hp; }
  short addXP(short pxp) { xp = xp + pxp; XPcheck(); return xp; }
  void XPcheck();  

  // Money methods
  inline const short getCredits () { return credits; }
  bool addCredits (short pcredits) { credits = credits + pcredits; }
  bool delCredits (short pcredits) { if (pcredits > credits) { return false; } credits = credits - pcredits; }

  // Inventory definition and methods
  Inventory inventory;
  Inventory * getInventory () { return (&inventory); } // Hackish? Yes. Works better than anything else, though.

  // Plan definition and methods
  Plan plan;
  Plan * getPlan () { return (&plan); }

protected:  
  string name;
  short charclass;
  short level;
  short str;
  short dex;
  short con;
  short inte;
  short wis;
  short cha;
  short hp;
  short maxhp;
  short ac;
  short xp;
  int credits;
};
  
Person::Person(string pname, short pcharclass, short pstr, short pdex, short pcon, short pint, short pwis, short pcha) :
  name(pname), charclass(pcharclass), level(1), str(pstr), dex(pdex), con(pcon), inte(pint), wis(pwis), cha(pcha), hp(5),
  maxhp(5), ac(10), xp(0), credits(0)
{
  Inventory inventory;
  Plan plan;
}

void Person::XPcheck() {
  while (xp > 1000) {
    short hpoff = 0;
    level = level + 1;
    xp = xp - 1000;
    switch (charclass) {
      // Classes:
      // 0 - Citizen
      // 1 - Fighter
      // 2 - Rogue
      // 3 - Sorcerer
    case 0:
      maxhp = maxhp + (con / 10);
      hpoff = maxhp % 1;
      maxhp = maxhp - hpoff;
      break;
    case 1:
      maxhp = maxhp + (con / 4);
      hpoff = maxhp % 1;
      maxhp = maxhp - hpoff;
      str = str + 1;
      break;
    case 2:
      maxhp = maxhp + (con / 6);
      hpoff = maxhp % 1;
      maxhp = maxhp - hpoff;
      dex = dex + 1;
      break;
    case 3:
      hpoff = maxhp % 1;
      maxhp = maxhp - hpoff;
      inte = inte + 1;
      wis = wis + 1;
    }
  }
}


// A Crowd is a group of people
// Generic Crowd node definition
class CrowdNode {
public:
  CrowdNode () {}
  virtual ~CrowdNode () {}
  virtual CrowdNode * addPerson (Person *thePerson) = 0;
  virtual void listPeople () = 0;
  virtual void delPerson (string) = 0;
  virtual int countPeople (int) = 0;
  virtual Person getPerson_name (string) = 0;
  virtual Person getPerson_order (int, int) = 0;
private:
};


// Body of the Crowd
class CrowdBody : public CrowdNode {
public:
  CrowdBody (Person *thePerson, CrowdNode *theNextNode) { myPerson = thePerson; nextNode = theNextNode; }
  virtual ~CrowdBody () { } //delete nextNode; delete myPerson; }
  virtual CrowdNode * addPerson (Person *thePerson);
  virtual void delPerson (string) {}
  virtual Person getPerson_name (string thePerson) { 
    if (myPerson->getName() == thePerson) return *myPerson; return nextNode->getPerson_name(thePerson); }
  virtual Person getPerson_order (int reqPerson, int thisPerson) {
    thisPerson++;
    if (reqPerson == thisPerson) return *myPerson; return nextNode->getPerson_order(reqPerson, thisPerson); }
  virtual int countPeople (int numPeople) { return nextNode->countPeople(numPeople + 1); }
  virtual void listPeople ();
private:
  Person *myPerson;
  CrowdNode *nextNode;
};

CrowdNode * CrowdBody::addPerson (Person *thePerson) {
  CrowdBody *newPerson = new CrowdBody (thePerson, this);
  return newPerson;
}

void CrowdBody::listPeople () {
  std::cout << myPerson->getName() << "\n";
  nextNode->listPeople();
}


// Tail of the Crowd
class CrowdTail : public CrowdNode {
public:
  CrowdTail () {}
  virtual ~CrowdTail () {}
  virtual CrowdNode * addPerson (Person *thePerson);
  virtual void delPerson (string thePerson) {}
  virtual Person getPerson_name (string thePerson) { }
  virtual Person getPerson_order (int reqPerson, int thisPerson) { }
  virtual void listPeople () {}
  virtual int countPeople (int numPeople) { return numPeople; }
};

CrowdNode * CrowdTail::addPerson (Person *thePerson) {
  CrowdBody *newPerson = new CrowdBody (thePerson, this);
  return newPerson;
}


// Head of the Crowd
class CrowdHead : public CrowdNode {
public:
  CrowdHead () { nextNode = new CrowdTail; }
  virtual ~CrowdHead () { delete nextNode; }
  virtual CrowdNode * addPerson (Person *thePerson) { nextNode = nextNode->addPerson(thePerson); }
  virtual void delPerson (string thePerson) {}
  virtual Person getPerson_name (string thePerson) { return nextNode->getPerson_name(thePerson); }
  virtual Person getPerson_order (int reqPerson, int thisPerson) { return nextNode->getPerson_order(reqPerson, -1); }
  virtual void listPeople () { nextNode->listPeople(); }
  virtual int countPeople (int numPeople) { return nextNode->countPeople(-1); /* This so the first item is item 0 */}


private:
  CrowdNode * nextNode;
};


// Crowd Class
class Crowd {
public:
  Crowd () { headNode = new CrowdHead; }
  ~Crowd () { delete headNode; }
  void addPerson (Person *thePerson) { headNode->addPerson(thePerson); }
  void delPerson (string thePerson) {}
  Person getPerson_name (string thePerson) { return headNode->getPerson_name(thePerson); }
  Person getPerson_order (int reqPerson) { return headNode->getPerson_order(reqPerson, -1); }
  void listPeople () { headNode->listPeople(); }
  int countPeople() { return headNode->countPeople(1337); /* This number gets dumped on the floor */}
private:  
  CrowdHead *headNode;
};
